<template>
	<view class="e-qrcode" :style="[boxStyle]">
		<template v-if="!isReload">
			<!-- canvas模式，默认 -->
			<template v-if="props.mode === 'canvas'">
				<!-- #ifndef APP-NVUE -->
				<canvas :id="canvasId" :canvas-id="canvasId" :style="[boxStyle]"></canvas>
				<!-- #endif -->
			</template>

			<!-- view模式，兼容 -->
			<view v-else-if="props.mode === 'view'" class="e-qrcode__view" :style="[boxStyle,{
	    'padding': `${props.margin}px`,
	    'background-color': props.backgroundColor
	    }]">
				<view class="e-qrcode__view__row" v-for="(row, rowIndex) in modules.length" :key="rowIndex">
					<view class="e-qrcode__view__col" v-for="(col, colIndex) in modules.length" :key="colIndex" :style="{
	      	'width': `${tileSize}px`,
	      	'height': `${tileSize}px`,
	      	'background-color': modules[rowIndex][colIndex] ? props.foregroundColor : props.backgroundColor
	      	}">
					</view>
				</view>
			</view>
		</template>

	</view>
</template>
<script lang="ts">
	import {defineComponent} from 'vue'
	import mpMixin from '../../libs/mixin/mpMixin'
	/**
	 * qrcode 二维码
	 * @description 弹出层容器，用于展示弹窗、信息提示等内容，支持上、下、左、右和中部弹出。组件只提供容器，内部内容由用户自定义
	 * @tutorial https://www.uviewui.com/components/popup.html
	 * @property {String}			mode					canvas|view
	 * @property {String}			text					二维码内容
	 * @property {Number}			size					二维码大小(单位px)
	 * @property {Number}			margin					填充边距
	 * @property {String}			backgroundColor			背景色
	 * @property {String}			foregroundColor			前景色
	 * @property {Number}			errorCorrectLevel		纠错等级
	 * @property {String}			fileType				导出的文件类型
	 */
	export default defineComponent({
		name: 'e-qrcode',
		mixins: [mpMixin]
	})
</script>

<script lang="ts" setup>
	import {
		ref,
		watch,
		computed,
		toRefs,
		getCurrentInstance,
		nextTick,
		onMounted
	} from "vue";
	import {
		useDefaultProps
	} from '../../libs/hooks'
	import {
		qrcodeProps,
		qrcodeEmits
	} from "./props";
	import {
		nanoid,
		uQRCode,
		isFunction
	} from "../../libs/utils";
	import componentsProps, {
		type DefaultProps
	} from "../../libs/config/componentsProps";

	const {
		qrcode: qrcodeDefaultProps
	} = toRefs(componentsProps);

	const _props = defineProps(qrcodeProps)

	const props = useDefaultProps < DefaultProps['qrcode'] > (_props, qrcodeDefaultProps);
	const emit = defineEmits(qrcodeEmits)

	const ctx = getCurrentInstance()

	const canvasId = nanoid(21, true)

	const boxStyle = computed(() => {
		return {
			'width': `${props.value.size}px`,
			'height': `${props.value.size}px`
		}
	})

	const modules = computed(() => {
		return uQRCode.getModules(props.value)
	})

	const tileSize = computed(() => {
		return (props.value.size - props.value.margin * 2) / modules.value.length
	})

	// 是否重载
	const isReload = ref(false)
	// 是否在绘制中
	const makeing = ref(false)
	
	let delegate: ((callback: Callback) => void) | null = null
	
	let delegateParams: Record < string, any > = {}

	type Callback = {
		success ? (e: UniNamespace.CanvasToTempFilePathRes) : void,
		fail ? (e: any) : void,
		complete ? (e: any) : void
	}

	let canvasContext: null | UniNamespace.CanvasContext = null

	const make = () => {
		if (makeing.value) {
			return
		}
		makeing.value = true
		if (props.value.mode === 'canvas') {
			// #ifndef APP-NVUE
			/* 获取绘图所需的上下文 */
			canvasContext = uni.createCanvasContext(canvasId, ctx)
			// #endif


			canvasContext.draw() // 清空之前的画布内容
			canvasContext.setFillStyle(props.value.backgroundColor)
			canvasContext.fillRect(0, 0, props.value.size, props.value.size)

			for (var row = 0; row < modules.value.length; row++) {
				for (var col = 0; col < modules.value.length; col++) {
					// 计算每一个小块的位置
					var x = col * tileSize.value + props.value.margin
					var y = row * tileSize.value + props.value.margin
					var w = tileSize.value
					var h = tileSize.value

					var style = modules.value[row][col] ? props.value.foregroundColor : props.value.backgroundColor
					canvasContext.setFillStyle(style)
					canvasContext.fillRect(x, y, w, h)
				}
			}

			canvasContext.draw(false, () => {
				// setTimeout(() => {
				complete()
				// }, 3000)
			})
		} else if (props.value.mode === 'view') {
			complete()
		}
	}

	const reload = () => {
		/* 重载组件 */
		isReload.value = true
		nextTick(() => {
			isReload.value = false
			nextTick(() => {
				setTimeout(() => {
					make()
				}, 150)
			})
		})
	}

	const complete = () => {
		let ages = {
			id: canvasId,
			text: props.value.text,
			mode: props.value.mode
		}
		makeing.value = false
		emit('complete', ages)
	}

	const toTempFilePath = (callback: Callback) => {
		if (makeing.value) {
			// 如果还在生成状态，那当前操作将托管到委托，监听生成完成后再通过委托复调当前方法
			delegate = toTempFilePath
			delegateParams = callback
			return
		} else {
			delegate = null
			delegateParams = {}
		}
		// #ifndef APP-NVUE
		uni.canvasToTempFilePath({
			canvasId,
			fileType: props.value.fileType,
			width: props.value.size,
			height: props.value.size,
			success: res => {
				isFunction(callback.success) && callback.success(res)
				isFunction(delegateParams.success) && delegateParams.success(res)
				
			},
			fail: err => {
				isFunction(callback.fail) && callback.fail(err)
				isFunction(delegateParams.fail) && delegateParams.fail(err)
			},
			complete: res => {
				isFunction(callback.complete) && callback.complete(res)
				isFunction(delegateParams.complete) && delegateParams.complete(res)
			}
		}, ctx)
		// #endif
	}

	onMounted(() => {
		nextTick(() => {
			make()
		})
	})


	watch(() => props.value, () => {
		reload()
	}, {
		deep: true
	})

	watch(() => makeing.value, (v) => {
		if (!v && isFunction(delegate)) {
			delegate(delegateParams)
		}
	})


	defineExpose({
		toTempFilePath
	})
</script>

<style lang="scss" scoped>
	@import '../../libs/theme/qrcode.scss';
</style>
